home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / QuickDraw / Restore Screen Cluts / ColorReset.c next >
Encoding:
C/C++ Source or Header  |  1994-11-09  |  45.3 KB  |  1,286 lines  |  [TEXT/MPS ]

  1. /******************************************************************************\
  2. *
  3. * Apple Macintosh Developer Technical Support
  4. *
  5. * Main program file
  6. *
  7. * Program: ColorImage
  8. * File:    ColorImage.c
  9. *
  10. * by:      Forrest Tanaka
  11. *
  12. * Copyright © 1988-1992 Apple Computer, Inc.
  13. * All rights reserved.
  14. *
  15. \******************************************************************************/
  16.  
  17.  
  18. /******************************************************************************\
  19. * Header Files
  20. \******************************************************************************/
  21.  
  22. #include <Desk.h>
  23. #include <DiskInit.h>
  24. #include <Errors.h>
  25. #include <Fonts.h>
  26. #include <Menus.h>
  27. #include <Resources.h>
  28. #include <ToolUtils.h>
  29. #include <QuickDraw.h>
  30. #include <Windows.h>
  31. #include <Events.h>
  32. #include <OSEvents.h>
  33. #include <AppleEvents.h>
  34. #include <GestaltEqu.h>
  35. #include <Packages.h>
  36. #include <Palettes.h>
  37. #include <Traps.h>
  38.  
  39. #include "EmergMem.h"
  40. #include "Exceptions.h"
  41. #include "ColorReset.h"
  42. #include "MenuHandler.h"
  43. #include "PictDocument.h"
  44. #include "WindowPositioner.h"
  45.  
  46.  
  47. /******************************************************************************\
  48. * Constants
  49. \******************************************************************************/
  50.  
  51. /* Disk initialization */
  52. #define kSysAlertLeft 80 /* Left coord of DIBadMount alert in screen coords */
  53. #define kSysAlertTop  80 /* Top coord of DIBadMount alert in screen coords */
  54.  
  55. /* EqualString convenience constants */
  56. #define kCaseSens true /* Pass to EqualString for case-sensitive check */
  57. #define kDiacSens true /* Pass to EqualString for diacritical-sens. check */
  58.  
  59. /* Constants for checking on command-. */
  60. #define kMaskModifiers 0xFE00     /* Mask for modifiers w/o command key */
  61. #define kMaskASCII1    0x00FF0000 /* get the key out of the ASCII1 byte */
  62. #define kMaskASCII2    0x000000FF /* get the key out of the ASCII2 byte */
  63.  
  64. /* Miscellaneous */
  65. #define kMinWindSize    128  /* Minimum size of a window */
  66. #define kMaxSleepTime   60   /* # ticks to wait between minor switches */
  67. #define kBecomingActive true /* Pass to DoActivateEvt; app becoming active */
  68.  
  69.  
  70. /******************************************************************************\
  71. * Macros
  72. \******************************************************************************/
  73.  
  74. /* Return status of bth bit of m */
  75. #define btst(m,b) ((m) & (1L << (b)))
  76.  
  77.  
  78. /******************************************************************************\
  79. * Global Variables
  80. \******************************************************************************/
  81.  
  82. Boolean gHasWNE;         /* True if WaitNextEvent is implemented */
  83. Boolean gQuitting;       /* True if user requested that this app quit */
  84. Boolean gWereInFront;    /* True if this application is frontmost */
  85. Boolean gFixMenus;       /* True if menus need fixing */
  86. Boolean gHasAppleEvents; /* True if Apple Events implemented */
  87. Boolean gHasCoolSF;      /* True if 7.0 Standard File routines available */
  88.  
  89. ControlActionUPP gActionProc;
  90.  
  91. QDBitsUPP        gQDBitsUPP;
  92. QDGetPicUPP      gQDGetPicUPP;
  93. QDPutPicUPP      gQDPutPicUPP;
  94.  
  95. #ifdef powerc
  96.    QDGlobals    qd;
  97. #endif
  98.  
  99.  
  100.  
  101. /******************************************************************************\
  102. * Private Function Prototypes
  103. \******************************************************************************/
  104.  
  105. main(void);
  106.  
  107. void StartUp(void);
  108.  
  109. void ShutDown(void);
  110.  
  111. void EventLoop(void);
  112.  
  113. long CalcSleepTime(void);
  114.  
  115. void DoMouseDown(EventRecord *anEvent);
  116.  
  117. void DoKeyDown(EventRecord *anEvent);
  118.  
  119. void DoDiskEvt(EventRecord *anEvent);
  120.  
  121. OSErr HandleAEquit(AppleEvent *quitAppleEvent,AppleEvent *reply, long  handlerRefCon);
  122.  
  123. OSErr DoneRequiredParams(AppleEvent *anAppleEvent);
  124.  
  125. Boolean IsDAWindow(WindowPtr aWindow);
  126.  
  127. void DoWindowDrag(EventRecord *anEvent,WindowPtr   clickedWindow);
  128.  
  129. void DoWindowGrow(EventRecord *anEvent,WindowPtr   clickedWindow);
  130.  
  131. void DoContentClick(EventRecord *anEvent,WindowPtr   clickedWindow);
  132.  
  133. void DoActivateEvt(WindowPtr eventWind,Boolean   becomingActive);
  134.  
  135. void DoWindowClose(EventRecord *anEvent,WindowPtr   eventWindow);
  136.  
  137. short MaxToolboxTrap(void);
  138.  
  139. TrapType GetTrapType(short theTrap);
  140.  
  141.  
  142. /******************************************************************************\
  143. * Public: main - Entry point to this application
  144. *
  145. * After the heap is initialized by allocating several master pointer blocks and
  146. * expanding the application’s heap to its maximum size, StartUp is called to
  147. * complete initialization.  The user is asked to open a Picture Document, and
  148. * then the main event loop is entered.
  149. \******************************************************************************/
  150.  
  151.  
  152. main()
  153. {
  154.     /* Prepare the heap */
  155.     MaxApplZone();
  156.     MoreMasters();
  157.     MoreMasters();
  158.     MoreMasters();
  159.     MoreMasters();
  160.     MoreMasters();
  161.     MoreMasters();
  162.     MoreMasters();
  163.     MoreMasters();
  164.  
  165.     /* Initialize the application */
  166.     StartUp();
  167.     
  168.     /* set up the ControlActionUPP */
  169.     gActionProc = NewControlActionProc((ProcPtr)ScrollActionProc);
  170.     
  171.     /* now set up the UPPs for QDProcs we use */
  172.     gQDBitsUPP   =  NewQDBitsProc(InfoBits);
  173.     gQDGetPicUPP =    NewQDGetPicProc(FileGetPic);
  174.     gQDPutPicUPP =    NewQDPutPicProc(FilePutPic);
  175.  
  176.     /* Ask the user for a Picture Document to open */
  177.     (void)DoOpenPictDoc();
  178.  
  179.     /* Execute the main event loop */
  180.     EventLoop();
  181.  
  182.     /* Shut down the application */
  183.     ShutDown();
  184.  
  185.     /* Return the ANSI way */
  186.     return 0;
  187. }
  188.  
  189.  
  190. /******************************************************************************\
  191. * StartUp - Do whatever has to be done to initialize the application
  192. *
  193. * This routine is called after the heap is initialized to initialize the
  194. * application.  This involves initializing the toolbox, emergency memory,
  195. * loading up the menus, validating the current environment, and initializing
  196. * global variables.  If any errors occur while doing this, StartUp displays
  197. * an alert telling the user what the error was and then ExitToShell is called.
  198. * This is an unusual way to react to errors, and I only do it here because it’s
  199. * so early in execution that there really isn’t much else that can be done.
  200. *
  201. * See EmergMem.h in this application for details about emergency memory.
  202. \******************************************************************************/
  203.  
  204.  
  205. void StartUp()
  206. {
  207.     short        result;  /* Result of alert; ignored */
  208.     long         aeAttrs; /* AppleEvent attributes */
  209.     long         sfAttrs; /* Standard File attributes */
  210.     OSErr        error;
  211.     ExceptionRec exception;
  212.     long         msgType;
  213.     long         msgCode;
  214.  
  215.     if (ExceptionEntry( /*<*/&exception, /*<*/&msgType, /*<*/&msgCode ))
  216.     {
  217.         result = ShowAlert( kStopAlert, rOKAlertID, msgType, msgCode );
  218.         ExitToShell();
  219.     }
  220.  
  221.     /* Initialize the toolbox */
  222.     InitGraf(&qd.thePort);
  223.     InitFonts();
  224.     InitWindows();
  225.     InitMenus();
  226.     TEInit();
  227.     InitDialogs( nil );
  228.  
  229.     /* Initialize emergency memory */
  230.     InitEmergMem();
  231.     if (FailLowMemory( 0 ))
  232.         Exception( &exception, rMemErrMessages, kMemErrAppOpenMsg );
  233.  
  234.     /* Initialize the menus */
  235.     error = StartMenus();
  236.     if (error == memFullErr || FailLowMemory( 0 ))
  237.         Exception( &exception, rMemErrMessages, kMemErrAppOpenMsg );
  238.     else if (error == resNotFound)
  239.         Exception( &exception, rResErrMessages, kResErrAppDamageMsg );
  240.     else if (error == dsSysErr)
  241.         Exception( &exception, rMiscErrMessages, kMiscErrUnknownMsg );
  242.  
  243.     /* Load and lock the disk-initialization package */
  244.     DILoad();
  245.  
  246.     /* See if WaitNextEvent is implemented */
  247.     gHasWNE = TrapExists( _WaitNextEvent );
  248.  
  249.     /* Check for the fancier capabilities */
  250.     error = Gestalt( gestaltAppleEventsAttr, /*<*/&aeAttrs );
  251.     if (error != noErr)
  252.         gHasAppleEvents = false;
  253.     else
  254.         gHasAppleEvents = btst( aeAttrs, gestaltAppleEventsPresent );
  255.     error = Gestalt( gestaltStandardFileAttr, /*<*/&sfAttrs );
  256.     if (error != noErr)
  257.         gHasCoolSF = false;
  258.     else
  259.         gHasCoolSF = btst( sfAttrs, gestaltStandardFile58 );
  260.  
  261.     /* Install the AppleEvent handler */
  262.     if (gHasAppleEvents)
  263.     {
  264.         error = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication,
  265.                 NewAEEventHandlerProc(HandleAEquit), 0, false );
  266.         if (error == memFullErr || FailLowMemory( 0 ))
  267.             Exception( &exception, rMemErrMessages, kMemErrAppOpenMsg );
  268.         else if (error != noErr)
  269.             Exception( &exception, rMiscErrMessages, kMiscErrUnknownMsg );
  270.     }
  271. }
  272.  
  273.  
  274. /******************************************************************************\
  275. * ShutDown - Do whatever has to be done to shut down the application
  276. *
  277. * This routine is called when the application is about to shut down.  It calls
  278. * ExitGraphics and ExitPrinting to shut down Sarano graphics and printing.
  279. \******************************************************************************/
  280.  
  281. static void ShutDown()
  282. {
  283. }
  284.  
  285.  
  286. /******************************************************************************\
  287. * EventLoop - Main event loop for this application
  288. *
  289. * This is the main event loop of this application.  During every iteration of
  290. * the event loop, the menus are kept up-to-date.  Also, NoEmergMem is called to
  291. * detect whether the emergency memory was used.  If it was, then RecoverEmergMem
  292. * is called in an attept to get it back.  If it can’t, then some commands could
  293. * be disabled until the memory can be recovered.
  294. \******************************************************************************/
  295.  
  296. static void EventLoop()
  297. {
  298.     EventRecord anEvent;     /* An incoming event */
  299.     Boolean     gotEvent;    /* True if a non-null event was received */
  300.     WindowPtr   lastWindow;  /* Pointer to front window during last iteration */
  301.     WindowPtr   currWindow;  /* Pointer to the current front window */
  302.     WindowPtr   eventWindow; /* Window involved in an incoming event */
  303.     Byte        osEvtKind;   /* Kind of OSEvt; mouse-moved or suspend/resume */
  304.  
  305.     gWereInFront = true;
  306.     gQuitting = false;
  307.     gFixMenus = true;
  308.     lastWindow = nil;
  309.     InitCursor();
  310.  
  311.     /* We loop until gQuitting is true */
  312.     while (!gQuitting)
  313.     {
  314.         /* Try to reallocate emergency memory if it’s been used */
  315.         if (NoEmergMem())
  316.             RecoverEmergMem();
  317.  
  318.         /* Fix the menus to reflect current conditions */
  319.         currWindow = FrontWindow();
  320.         if (currWindow != lastWindow || gFixMenus)
  321.         {
  322.             FixMenus();
  323.             lastWindow = currWindow;
  324.             gFixMenus = false;
  325.         }
  326.  
  327.         /* It’s time to get and examine an event */
  328.         if (gHasWNE)
  329.             gotEvent = WaitNextEvent( everyEvent, /*<*/&anEvent,
  330.                     CalcSleepTime(), nil );
  331.         else
  332.         {
  333.             SystemTask();
  334.             gotEvent = GetNextEvent( everyEvent, /*<*/&anEvent );
  335.         }
  336.         if (gotEvent)
  337.             switch (anEvent.what)
  338.             {
  339.                 case mouseDown:
  340.                     DoMouseDown( &anEvent );
  341.                     break;
  342.                 case keyDown:
  343.                 case autoKey:
  344.                     DoKeyDown( &anEvent );
  345.                     break;
  346.                 case updateEvt:
  347.                     DoUpdateEvt( &anEvent );
  348.                     break;
  349.                 case diskEvt:
  350.                     DoDiskEvt( &anEvent );
  351.                     break;
  352.                 case activateEvt:
  353.                     DoActivateEvt( (WindowPtr)anEvent.message,
  354.                             anEvent.modifiers & activeFlag );
  355.                     break;
  356.                 case kHighLevelEvent:
  357.                     (void)AEProcessAppleEvent( &anEvent );
  358.                     break;
  359.                 case osEvt:
  360.                     osEvtKind = (anEvent.message >> 24) & 0x0FF;
  361.                     if (osEvtKind == suspendResumeMessage)
  362.                     {
  363.                         /* It’s a suspend/resume event; suspend or resume? */
  364.                         eventWindow = FrontWindow();
  365.                         if ((anEvent.message & 1) != 0)
  366.                         {
  367.                             /* Resume event; set the cursor and activate front window */
  368.                             InitCursor();
  369.                             if (eventWindow != nil)
  370.                                 DoActivateEvt( eventWindow, kBecomingActive );
  371.                             gWereInFront = true;
  372.                             }
  373.                         else
  374.                         {
  375.                             /* Suspend event; deactivate the front window */
  376.                             if (eventWindow != nil)
  377.                                 DoActivateEvt( eventWindow, !kBecomingActive );
  378.                             gWereInFront = false;
  379.                         }
  380.                     }
  381.                     break;
  382.             }
  383.     }
  384. }
  385.  
  386.  
  387. /******************************************************************************\
  388. * CalcSleepTime - Calculate the number of ticks for WaitNextEvent to sleep
  389. *
  390. * WaitNextEvent takes a parameter that specifies the number of ticks that this
  391. * application allows WaitNextEvent to service other open applications.  This is
  392. * just a guideline; the actual amount of time that WaitNextEvent takes could be
  393. * shorter or longer than our specification, depending on how heavy the system
  394. * load is and on how long other applications take.
  395. *
  396. * If the front window is a desk accessory window, CalcSleepTime returns 0 which
  397. * specifies that this application wants as much time as possible.  Under
  398. * MultiFinder, desk accessories are normally running in the DA Handler layer,
  399. * so this really doesn’t matter that much.  Under system software version 7.0,
  400. * desk accessories never run in our layer, so this code never gets executed.
  401. \******************************************************************************/
  402.  
  403. static long CalcSleepTime()
  404. {
  405.     long sleepTime; /* Number of ticks to sleep */
  406.  
  407.     if (IsDAWindow( FrontWindow() ))
  408.         sleepTime = 0;
  409.     else
  410.         sleepTime = kMaxSleepTime;
  411.  
  412.     return sleepTime;
  413. }
  414.  
  415.  
  416. /******************************************************************************\
  417. * DoMouseDown - Mouse-down event dispatcher
  418. *
  419. * When a mouseDown event is received in the main event loop, this routine is
  420. * called to determine which area on the screens the mouseDown was, and to
  421. * dispatch to the appropriate routine to handle mouseDown events in that area.
  422. * The mouseDown event is passed in the anEvent parameter.
  423. *
  424. * See MenuHandler.h for routines that handle mouse-down events in the menu bar.
  425. \******************************************************************************/
  426.  
  427. static void DoMouseDown(
  428.     EventRecord *anEvent) /* Contains mouse-down event */
  429. {
  430.     short     clickArea;   /* Area of the screen that was clicked */
  431.     WindowPtr eventWindow; /* Pointer the clicked window, if any */
  432.  
  433.     /* Find clicked area of screen or window */
  434.     clickArea = FindWindow( anEvent->where, /*<*/&eventWindow );
  435.  
  436.     /* Jump to mouseDown-handling routine appropriate for screen area */
  437.     switch (clickArea)
  438.     {
  439.         case inMenuBar:
  440.             DoMenuChoice( MenuSelect( anEvent->where ) );
  441.             break;
  442.         case inSysWindow:
  443.             SystemClick( anEvent, eventWindow );
  444.             break;
  445.         case inContent:
  446.             DoContentClick( anEvent, eventWindow );
  447.             break;
  448.         case inDrag:
  449.             DoWindowDrag( anEvent, eventWindow );
  450.             break;
  451.         case inGrow:
  452.             DoWindowGrow( anEvent, eventWindow) ;
  453.             break;
  454.         case inGoAway:
  455.             DoWindowClose( anEvent, eventWindow );
  456.             break;
  457.         default:
  458.             break;
  459.     }
  460. }
  461.  
  462.  
  463. /******************************************************************************\
  464. * DoKeyDown - Key-down event dispatcher
  465. *
  466. * When a keyDown or autoKey event is received in the main event loop, this
  467. * routine is called to determine whether key is a command-key equivalent for a
  468. * menu item or not.  If the command key isn’t down, then the key stroke is
  469. * ignored.  Otherwise, MenuKey is called to get the menu ID and item number
  470. * of the menu item that corresponds to the command key, if any.  Then
  471. * DoMenuChoice is called to dispatch to the appropriate routine for the chosen
  472. * menu item.  The keyDown or autoKey event is passed in anEvent.
  473. \******************************************************************************/
  474.  
  475. static void DoKeyDown(
  476.     EventRecord *anEvent) /* Contains the key-down event */
  477. {
  478.     char theKey; /* ASCII code of key that was pressed */
  479.  
  480.     /* Get the ASCII code of the pressed key */
  481.     theKey = anEvent->message & charCodeMask;
  482.  
  483.     /* If anEvent was keyDown and command key was down, it’s menu command */
  484.     if (anEvent->what == keyDown && (anEvent->modifiers & cmdKey))
  485.         DoMenuChoice( MenuKey( theKey ) );
  486. }
  487.  
  488.  
  489. /******************************************************************************\
  490. * DoDiskEvt - Handle a disk-insert event
  491. *
  492. * This routine is called whenever this application receives an event indicating
  493. * that a disk was inserted.  If the disk can’t be mounted, the message field of
  494. * the event reflects the error, and we call DIBadMount to allow the user to
  495. * format the disk.
  496. \******************************************************************************/
  497.  
  498. static void DoDiskEvt(
  499.     EventRecord *anEvent) /* Disk-insert event */
  500. {
  501.     Point cornerPoint; /* Top-left corner of DIBadMount alert */
  502.  
  503.     if (hiWord( anEvent->message ) != noErr)
  504.     {
  505.         SetPt( /*<*/&cornerPoint, kSysAlertLeft, kSysAlertTop );
  506.         (void)DIBadMount( cornerPoint, anEvent->message );
  507.     }
  508. }
  509.  
  510.  
  511. /******************************************************************************\
  512. * Private: HandleAEquit - Handler for 'quit' AppleEvent
  513. *
  514. * This is the AppleEvent handler for the 'quit' AppleEvent as passed in the
  515. * quitAppleEvent parameter by the AppleEvent Manager.  The DoQuit routine is
  516. * called which causes this application to quit at the start of the next
  517. * iteration of the main event loop.
  518. *
  519. * Though the quit AppleEvent doesn’t contain any parameters, the standard thing
  520. * to do in reaction to any AppleEvent is to check to see if there are any
  521. * required parameters in the AppleEvent that this routine doesn’t recognise.
  522. * DoneRequiredParms checks for this condition and returns an error if there are
  523. * in fact required parameters in the AppleEvent or if some other error occurs
  524. * during the check.
  525. \******************************************************************************/
  526.  
  527. static      OSErr HandleAEquit(
  528.     AppleEvent *quitAppleEvent, /* Contains the ‘quit’ AppleEvent */
  529.     AppleEvent *reply,          /* Returns reply; ignored */
  530.     long       handlerRefCon)   /* Application-defined parameter; ignored */
  531. {
  532. #pragma unused(reply,handlerRefCon)
  533.     OSErr error;
  534.  
  535.     /* quit AE has no parms, but check in case the client requires any */
  536.     error = DoneRequiredParams( quitAppleEvent );
  537.     if (error == noErr)
  538.         /* No extra parameters; handle Quit command */
  539.         DoQuit();
  540.  
  541.     return error;
  542. }
  543.  
  544.  
  545. /******************************************************************************\
  546. * DoneRequiredParams - Done processing required params; OK?
  547. *
  548. * DoneRequiredParams checks to see if the AppleEvent specified by the
  549. * anAppleEvent parameter has any required parameters that we haven’t yet
  550. * processed.  If there aren’t any left, then noErr is returned.  If there are
  551. * required parameters that haven’t been processed yet, then errAEEventNotHandled
  552. * is returned.  If any other errors occur, then that error code is returned.
  553. \******************************************************************************/
  554.  
  555. static OSErr DoneRequiredParams(
  556.     AppleEvent *anAppleEvent) /* AppleEvent being checked */
  557. {
  558.     DescType typeCode;   /* Type of AppleEvent attribute found; ignored */
  559.     Size     actualSize; /* Actual size of parameters; ignored */
  560.     OSErr    error;
  561.  
  562.     /* Are there any required parameters in AppleEvent we didn’t process? */
  563.        error = AEGetAttributePtr(
  564.                anAppleEvent,
  565.             keyMissedKeywordAttr,
  566.             typeWildCard,
  567.             /*<*/&typeCode,
  568.             nil,
  569.             0,
  570.             /*<*/&actualSize );
  571.     if (error == errAEDescNotFound)
  572.         /* No required parameters left, so no error */
  573.         error = noErr;
  574.     else if (error == noErr)
  575.         /* There was at least one required parameter we didn’t process */
  576.         error = errAEEventNotHandled;
  577.  
  578.     return error;
  579. }
  580.  
  581.  
  582. /******************************************************************************\
  583. * Public: DoQuit
  584. *
  585. * Each open window is checked to see what kind it is.  If a window is a
  586. * Document window, DoCloseDoc is called to close it.  If the window is a
  587. * desk accessory’s window, then CloseDeskAcc is called to close it.  This
  588. * process continues until all windows are closed.  Then the gQuitting global
  589. * variable is set to true, terminating the main event loop.
  590. \******************************************************************************/
  591.  
  592. void DoQuit()
  593. {
  594.     WindowPtr aWindow; /* Pointer to each window in the window list */
  595.  
  596.     aWindow = FrontWindow();
  597.  
  598.     /* Keep closing a window until there are no windows left */
  599.     while (aWindow != nil)
  600.     {
  601.         if (IsDAWindow( aWindow ))
  602.             CloseDeskAcc( ((WindowPeek)aWindow)->windowKind );
  603.         else
  604.             CloseWindow( aWindow );
  605.         aWindow = FrontWindow();
  606.     }
  607.  
  608.     /* Tell the main event loop that we’re done */
  609.     gQuitting = true;
  610. }
  611.  
  612.  
  613. /******************************************************************************\
  614. * Public: IsDAWindow
  615. *
  616. * The windowKind field of any window belonging to a desk accessory is negative,
  617. * so that’s how IsDAWindow decides whether a window belongs to a desk accessory
  618. * or not.
  619. \******************************************************************************/
  620.  
  621. Boolean IsDAWindow(
  622.     WindowPtr aWindow) /* Pointer to the window being tested */
  623. {
  624.     if (aWindow == nil)
  625.         return false;
  626.     else
  627.         return ((WindowPeek)aWindow)->windowKind < 0;
  628. }
  629.  
  630.  
  631. /******************************************************************************\
  632. * Private: DoWindowDrag - Allow the user to drag a window around
  633. *
  634. * When it’s been detected that the user clicked in the title bar of a window,
  635. * DoWindowDrag is called.  It allows the user to drag a window over the entire
  636. * desktop area, and the window is moved to wherever the user let it go.  Windows
  637. * behind the front window can be dragged as well, unless the front window is a
  638. * modal dialog box.
  639. *
  640. * The mouseDown event that turned out to be a request to drag the window is
  641. * passed in the anEvent parameter.  A pointer to the window whose title bar got
  642. * clicked is passed in clickedWindow.
  643. *
  644. * A rectangle that covers all screen can be retrieved from the desktop region’s
  645. * rgnBBox.  The desktop region can be retrieved by calling GetGrayRgn.
  646. \******************************************************************************/
  647.  
  648. static void DoWindowDrag(
  649.     EventRecord *anEvent,      /* Mouse-down event in the title bar */
  650.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  651. {
  652.     Rect dragBounds; /* Window can be dragged over this rectangle */
  653.  
  654.     /* (**GetGrayRgn()).rgnBBox covers the desktop over all screens */
  655.     dragBounds = (**GetGrayRgn()).rgnBBox;
  656.     DragWindow( clickedWindow, anEvent->where, &dragBounds );
  657. }
  658.  
  659.  
  660. /******************************************************************************\
  661. * Private: DoWindowGrow - Handle a mouse click in the grow box of a window
  662. *
  663. * When it’s been detected that the user clicked in the grow box of a window,
  664. * DoWindowGrow is called.  It allows the user to change the size of the clicked
  665. * window.
  666. *
  667. * The mouseDown event that turned out to be a request to resize the window is
  668. * passed in the anEvent parameter.  A pointer to the window whose grow box got
  669. * clicked is passed in clickedWindow.
  670. \******************************************************************************/
  671.  
  672. static void DoWindowGrow(
  673.     EventRecord *anEvent,      /* Mouse-down event in the title bar */
  674.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  675. {
  676.     /* Have the window react to the resize */
  677.     if (IsPictDocWindow( clickedWindow ))
  678.         GrowPictDoc( clickedWindow, anEvent );
  679. }
  680.  
  681.  
  682. /******************************************************************************\
  683. * Private: DoContentClick - Handle a click in a window
  684. *
  685. * When it’s been detected that the user clicked in the content region of a
  686. * window, DoContentClick is called.  This routine determines the kind of window
  687. * that was clicked and dispatches control to the routine that handles mouse
  688. * clicks in that kind of window.
  689. *
  690. * The mouseDown event that turned out to be a window content click is passed
  691. * in the anEvent parameter.  A pointer to the window whose content region got
  692. * clicked is passed in clickedWindow.
  693. *
  694. * As new kinds of windows are added to this application, this routine will have
  695. * to be able to detect the new kind of window and dispatch to the routine that
  696. * handles clicks in that kind of window.
  697. \******************************************************************************/
  698.  
  699. static void DoContentClick(
  700.     EventRecord *anEvent,      /* Mouse-down event in the window’s content */
  701.     WindowPtr   clickedWindow) /* Pointer to the window that was clicked */
  702. {
  703. #pragma unused(anEvent)
  704.     WindowPtr currWindow; /* Pointer to the current front window */
  705.  
  706.     currWindow = FrontWindow();
  707.  
  708.     /* Clicked window not in front; activate it */
  709.     if (currWindow != clickedWindow)
  710.         SelectWindow( clickedWindow );
  711.     else
  712.     {
  713.         if (IsPictDocWindow( clickedWindow ))
  714.             ClickPictDoc( clickedWindow, anEvent );
  715.     }
  716. }
  717.  
  718.  
  719. /******************************************************************************\
  720. * Public: DoUpdateEvt
  721. *
  722. * As new kinds of windows are added to this application, this routine will have
  723. * to be able to detect the new kind of window and dispatch to the routine that
  724. * handles update events in that kind of window.
  725. \******************************************************************************/
  726.  
  727. void DoUpdateEvt(
  728.     EventRecord *anEvent) /* Update event */
  729. {
  730.     WindowPtr eventWindow; /* Pointer to the window to update */
  731.  
  732.     /* Get a pointer to the window that needs an update */
  733.     eventWindow = (WindowPtr)anEvent->message;
  734.  
  735.     /* Update the window that needs it */
  736.     SetPort( eventWindow );
  737.     BeginUpdate( eventWindow );
  738.     if (IsPictDocWindow( eventWindow ))
  739.         DrawPictDoc( eventWindow );
  740.     EndUpdate( eventWindow );
  741. }
  742.  
  743.  
  744. /******************************************************************************\
  745. * Public: DoActivateEvt
  746. *
  747. * As new kinds of windows are added to this application, this routine will have
  748. * to be able to detect the new kind of window and dispatch to the routine that
  749. * handles activate events in that kind of window.
  750. \******************************************************************************/
  751.  
  752. void DoActivateEvt(
  753.     WindowPtr eventWindow,    /* Window being (de)activated */
  754.     Boolean   becomingActive) /* True if window is becoming activated */
  755. {
  756.     if (IsPictDocWindow( eventWindow ))
  757.         ActivatePictDoc( eventWindow, becomingActive );
  758. }
  759.  
  760.  
  761. /******************************************************************************\
  762. * Private: DoWindowClose - Handle a click in the close box of a window
  763. *
  764. * This routine should be called when the user clicks in the close box of the
  765. * window specified by eventWind.  The mouse is tracked until the user releases
  766. * the mouse button.  If the user released the mouse button while the mouse was
  767. * in the close box, then DoCloseDoc determines the kind of window that the user
  768. * clicked the close box on, and the routine that handles the closing of that
  769. * kind of window is called.  anEvent contains the mouse-down event that was
  770. * determined to be a mouse click in the window.
  771. *
  772. * As new kinds of windows are added to this application, this routine will have
  773. * to be able to detect the new kind of window and dispatch to the routine that
  774. * handles close requests for that kind of window.
  775. \******************************************************************************/
  776.  
  777. static void DoWindowClose(
  778.     EventRecord *anEvent,    /* Mouse-down event in the close box */
  779.     WindowPtr   eventWindow) /* Pointer to the window that was clicked */
  780. {
  781.     if (TrackGoAway( eventWindow, anEvent->where ))
  782.         if (IsPictDocWindow( eventWindow ))
  783.             DoClosePictDoc( eventWindow );
  784. }
  785.  
  786.  
  787. /******************************************************************************\
  788. * Public: ShowAlert
  789. *
  790. * To position the alert before it’s displayed, the ALRT resource is loaded
  791. * before it’s displayed, and its boundsRect is put into the proper position
  792. * through the CenterScreenRect routine.  Because this modifies the ALRT
  793. * resource in memory and because ALRT resources are normally purgeable, it must
  794. * be made unpurgeable until the alert is dismissed.
  795. \******************************************************************************/
  796.  
  797. short ShowAlert(
  798.     short alertType,    /* Type of alert to display */
  799.     short buttonOption, /* Button options for alert */
  800.     short messageClass, /* Class of message to display in alert */
  801.     short messageIndex) /* Index of message to display in alert */
  802. {
  803.     Str255     aMessage;    /* Contents of message to place in alert */
  804.     AlertTHndl alertHandle; /* Handle to the 'ALRT' resource for this alert */
  805.     Rect       alertRect;   /* Rectangle of alert */
  806.     short      itemHit;     /* Item number of clicked item */
  807.     SignedByte savedState;  /* Saves state alertHandle */
  808.  
  809.     /* Put the specified message into the dialog parameter text */
  810.     if (messageIndex != 0)
  811.     {
  812.         GetIndString( /*<*/aMessage, messageClass, messageIndex );
  813.         ParamText( aMessage, "\P", "\P", "\P" );
  814.     }
  815.  
  816.     /* Show the stop alert */
  817.     InitCursor();
  818.  
  819.     /* Center and display the alert */
  820.     alertHandle = (AlertTHndl)Get1Resource( 'ALRT', buttonOption );
  821.     if (alertHandle != nil)
  822.     {
  823.         /* Must make alert unpurgeable because we’re modifying it in memory */
  824.         savedState = HGetState( (Handle)alertHandle );
  825.         HNoPurge( (Handle)alertHandle );
  826.  
  827.         /* Put the rectangle of the alert into alert position */
  828.         alertRect = (**alertHandle).boundsRect;
  829.         PositionScreenRect( /*◊*/&alertRect, kMainScreenPos, kAlertPos,
  830.                 nil, 0, 0 );
  831.         (**alertHandle).boundsRect = alertRect;
  832.  
  833.         /* Present the alert */
  834.         if (alertType == kGenericAlert)
  835.             itemHit = Alert( buttonOption, nil );
  836.         else if (alertType == kNoteAlert)
  837.             itemHit = NoteAlert( buttonOption, nil );
  838.         else if (alertType == kCautionAlert)
  839.             itemHit = CautionAlert( buttonOption, nil );
  840.         else if (alertType == kStopAlert)
  841.             itemHit = StopAlert( buttonOption, nil );
  842.  
  843.         /* Restore the state of alertHandle */
  844.         HSetState( (Handle)alertHandle, savedState );
  845.     }
  846.  
  847.     return itemHit;
  848. }
  849.  
  850.  
  851. /******************************************************************************\
  852. * Public: TrapExists
  853. *
  854. * Traps with trap word of $AAXX or $ABXX are treated as being identical to $A8XX
  855. * and $A9XX if Color QuickDraw isn’t implemented, so we check for this case
  856. * first.  We explicitly check to see if the trap word has a value greater than
  857. * the largest possible trap word on this machine.  If it is, then the trap is
  858. * automatically considered to be unimplemented.
  859. \******************************************************************************/
  860.  
  861. Boolean TrapExists(
  862.     short theTrap) /* Trap word being tested */
  863. {
  864.     TrapType theTrapType; /* The trap type of theTrap */
  865.  
  866.     /* If it’s a CQD trap but the trap table is too small, assume unimp. */
  867.     theTrapType = GetTrapType( theTrap );
  868.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >=
  869.             MaxToolboxTrap()))
  870.         theTrap = _Unimplemented;
  871.  
  872.     /* Return true if trap is implemented */
  873.     return NGetTrapAddress( _Unimplemented, ToolTrap ) !=
  874.             NGetTrapAddress( theTrap, theTrapType );
  875. }
  876.  
  877.  
  878. /******************************************************************************\
  879. * Private: MaxToolboxTrap - Determine max trap number available
  880. *
  881. * Depending upon whether Color QuickDraw is implemented, the maximum trap number
  882. * is either $0200 or $0400.  This routine tests to see which is the case by
  883. * testing _InitGraf (trap $A86E) against trap $AA6E.  If the trap table is the
  884. * bigger one, trap $AA6E always points either to Unimplemented or some other
  885. * trap.  If the trap table is the smaller one, then $AA6E evaluates to the same
  886. * trap as _InitGraf.  by comparing the address of the InitGraf trap against the
  887. * address of the $AA6E trap, we can determine whether the trap table is the
  888. * bigger one or the smaller one.  If we have the bigger trap table, then $0400
  889. * is returned.  If it’s the smaller trap table, then $0200 is returned.
  890. *
  891. * Some of you might think that it’s be a lot simpler by testing to see whether
  892. * Color QuickDraw is implemented or not.  Actually, I kind of think so too, but
  893. * there are changes to the system software version 7.0 trap dispatcher that
  894. * might make that test invalid, so I don’t know.  I didn’t write this, I just
  895. * use it.
  896. \******************************************************************************/
  897.  
  898. static short MaxToolboxTrap()
  899. {
  900.     if (NGetTrapAddress( _InitGraf, ToolTrap ) ==
  901.             NGetTrapAddress(0xAA6E, ToolTrap))
  902.         return 0x0200;
  903.     else
  904.         return 0x0400;
  905. }
  906.  
  907.  
  908. /******************************************************************************\
  909. * Private: GetTrapType - Determine whether a trap is OS trap or Toolbox trap
  910. *
  911. * This routine tests to see whether the trap specified by theTrap is an
  912. * operating system trap or a toolbox trap.  Operating system trap words begin
  913. * with $A0 or $A1 while toolbox traps begin with $A8, $A9, $AA, or $AB.  By
  914. * simply testing bit 11 of the trap word, we can determine which kind of trap
  915. * theTrap is.  If it’s an operating system trap, then OSTrap is returned.  If
  916. * it’s a toolbox trap, then ToolTrap is returned.
  917. \******************************************************************************/
  918.  
  919. static TrapType GetTrapType(
  920.     short theTrap) /* Trap word being tested */
  921. {
  922.     /* OS traps start with A0 or A1, Toolbox traps with A8, A9, AA, or AB */
  923.     if ((theTrap & 0x0800) == 0)
  924.         return OSTrap;
  925.     else
  926.         return ToolTrap;
  927. }
  928.  
  929.  
  930. /******************************************************************************\
  931. * Public: FileSpecGet
  932. *
  933. \******************************************************************************/
  934.  
  935. Boolean FileSpecGet(
  936.     FileFilterProcPtr fileFilter, /* Pointer to routine to filter files */
  937.     short             numTypes,   /* Number of files types in typeList */
  938.     SFTypeList        typeList,   /* Type of files to offer */
  939.     StandardFileReply *retReply)  /* Returns information about file to get */
  940. {
  941.     DialogTHndl sfTemplate;  /* Template for Standard File dialog */
  942.     Rect        sfRect;      /* Rectangle of Standard File dialog */
  943.     SFReply     oldReply;    /* Old-style reply record */
  944.  
  945.     if (gHasCoolSF)
  946.         StandardGetFile( fileFilter, numTypes, typeList, /*<*/retReply );
  947.     else
  948.     {
  949.         /* Center the rectangle of the Standard File dialog */
  950.         sfTemplate = (DialogTHndl)GetResource( 'DLOG', getDlgID );
  951.         sfRect = (**sfTemplate).boundsRect;
  952.         PositionScreenRect( &sfRect, kMainScreenPos, kAlertPos,
  953.                 nil, 0, 0 );
  954.  
  955.         /* Present the Standard File dialog */
  956.         SFGetFile( topLeft( sfRect ), "\P", fileFilter, numTypes, typeList, nil,
  957.                 /*<*/&oldReply );
  958.  
  959.         /* Convert the old reply to a new reply record */
  960.         (void)ConvertOldToNewSFReply( &oldReply, retReply );
  961.     }
  962.     return retReply->sfGood;
  963. }
  964.  
  965.  
  966. /******************************************************************************\
  967. * Public: ConvertOldToNewSFReply
  968. *
  969. * GetWDInfo is used to convert the working directory reference number that’s
  970. * in the oldReply->vRefNum field to a real volume reference number and directory
  971. * ID so that these values can be stuffed into the new reply record’s FSSpec.
  972. \******************************************************************************/
  973.  
  974. OSErr ConvertOldToNewSFReply(
  975.     SFReply           *oldReply, /* Old reply record to be converted */
  976.     StandardFileReply *newReply) /* Returns the converted reply record */
  977. {
  978.     short   volRef;     /* Volume ref number (NOT WD ref num) of file */
  979.     long    dirID;      /* Directory ID of the file */
  980.     long    procID;     /* WD Proc ID; ignored */
  981.     FInfo   finderInfo; /* Finder info for a file; ignored */
  982.     Boolean replacing;  /* True if the specified file exists */
  983.     OSErr   error;
  984.  
  985.     /* Get the real volume reference number of directory ID of file */
  986.     error = GetWDInfo( oldReply->vRefNum, /*<*/&volRef,
  987.             /*<*/&dirID, /*<*/&procID );
  988.     if (error != noErr)
  989.         return error;
  990.  
  991.     /* Probe to see if the specified file exists */
  992.     error = HGetFInfo( volRef, dirID, oldReply->fName, /*<*/&finderInfo ); 
  993.     if (error == fnfErr)
  994.         replacing = false;
  995.     else if (error == noErr)
  996.         replacing = true;
  997.     else
  998.         return error;
  999.  
  1000.     /* Fill out the new reply record */
  1001.     newReply->sfGood = oldReply->good;
  1002.     newReply->sfReplacing = replacing;
  1003.     newReply->sfType = oldReply->fType;
  1004.     newReply->sfFile.vRefNum = volRef;
  1005.     newReply->sfFile.parID = dirID;
  1006.     BlockMove( (Ptr)&oldReply->fName, (Ptr)&newReply->sfFile.name,
  1007.             oldReply->fName[0] + 1 );
  1008.     newReply->sfScript = iuSystemScript;
  1009.     newReply->sfFlags = 0;
  1010.     newReply->sfIsFolder = false;
  1011.     newReply->sfIsVolume = false;
  1012.     newReply->sfReserved1 = 0;
  1013.     newReply->sfReserved2 = 0;
  1014.  
  1015.     return noErr;
  1016. }
  1017.  
  1018.  
  1019. /******************************************************************************\
  1020. * Public: EqualFSSpec
  1021. *
  1022. * To compare names, I’m using EqualString with no case sensitivity, but with
  1023. * sensitivity to diacriticals.  This isn’t usually the recommended way of
  1024. * comparing strings, because the Script Manager has routines for comparing
  1025. * strings in a more sophisticated, localizable way.  But the File Manager uses
  1026. * _CmpString, which is the assembly language equivalent of EqualString, so
  1027. * that’s the way I must do things here.
  1028. \******************************************************************************/
  1029.  
  1030. Boolean EqualFSSpec(
  1031.     FSSpecPtr spec0, /* First FSSpec being compared */
  1032.     FSSpecPtr spec1) /* Second FSSpec being compared */
  1033. {
  1034.     return (spec0->vRefNum == spec1->vRefNum) &&
  1035.            (spec0->parID == spec1->parID) &&
  1036.            (EqualString(spec0->name, spec1->name, !kCaseSens, kDiacSens));
  1037. }
  1038.  
  1039.  
  1040. /******************************************************************************\
  1041. * Public: CmdPeriodEvent
  1042. *
  1043. * This routine uses the technique documented in Macintosh Technical Note #263
  1044. * to determine whether the event passed in the anEvent parameter contains a
  1045. * command-period event or not, regardless of the current keyboard layout.
  1046. *
  1047. * The problem that this routine solves is that some keyboards (mainly some
  1048. * European keyboards) require the shift key to be pressed to generate the
  1049. * period, but the command key turns off the shift key, making it impossible to
  1050. * see the period.  To fix this, this routine calls the KeyTranslate routine which
  1051. * maps a virtual keycode and modifier keys to the ASCII code of the typed
  1052. * character.  The modifier keys passed to KeyTranslate are the same as in the
  1053. * event record, but the command key modifier bit is stripped out.  This makes
  1054. * KeyTranslate think the command key wasn’t held down, and so the influence of other
  1055. * modifier keys is unaffected.
  1056. \******************************************************************************/
  1057.  
  1058. Boolean CmdPeriodEvent(
  1059.     EventRecord *anEvent) /* Event being tested */
  1060. {
  1061.     long    lowChar;      /* Low character of keyInfo */
  1062.     long    highChar;     /* High character of keyInfo */
  1063.     Handle  hKCHR;        /* Handle to the currently-used KCHR */
  1064.     long    keyInfo;      /* Key information returned from KeyTranslate */
  1065.     long    keyScript;    /* Script of the current keyboard */
  1066.     long    state;        /* State used for KeyTranslate */
  1067.     short   virtualKey;   /* Virtual keycode of the character-generating key */
  1068.     short   keyCode;      /* Keycode of the character-generating key */
  1069.     Boolean gotCmdPeriod; /* True if detected command-. */
  1070.  
  1071.     gotCmdPeriod = false;
  1072.     if (anEvent->what == keyDown || anEvent->what == autoKey)
  1073.     {
  1074.         if (anEvent->modifiers & cmdKey)
  1075.         {
  1076.             /* Get the virtual keycode of the code-generating key */
  1077.             virtualKey = (anEvent->message & keyCodeMask) >> 8;
  1078.  
  1079.             /* Get a copy of the current KCHR */
  1080.             keyScript = GetScript( GetScriptManagerVariable( smKeyScript ), smScriptKeys);
  1081.             hKCHR = GetResource('KCHR', keyScript);
  1082.             if (hKCHR != nil)
  1083.             {
  1084.                 /* AND out the command key and OR in the virtualKey */
  1085.                 keyCode = (anEvent->modifiers & kMaskModifiers) | virtualKey;
  1086.  
  1087.                 /* Get key information */
  1088.                 state = 0;
  1089.                 keyInfo = KeyTranslate( *hKCHR, keyCode, &state );
  1090.             }
  1091.             else
  1092.                 keyInfo = anEvent->message;
  1093.  
  1094.             /* Check both low and high bytes of keyInfo for period */
  1095.             lowChar = keyInfo & kMaskASCII2;
  1096.             highChar = (keyInfo & kMaskASCII1) >> 16;
  1097.             if (lowChar == '.' || highChar == '.')
  1098.                 gotCmdPeriod = true;
  1099.         }
  1100.     }
  1101.  
  1102.     return gotCmdPeriod;
  1103. }
  1104.  
  1105.  
  1106. /******************************************************************************\
  1107. * Public: FakeButtonHit
  1108. *
  1109. * HiliteControl is used to hilight and unhilight a button.
  1110. \******************************************************************************/
  1111.  
  1112. void FakeButtonHit(
  1113.     ControlHandle buttonControl) /* Handle to button whose click we’re faking */
  1114. {
  1115.     long lastTicks; /* TickCount at end of delay; ignored */
  1116.  
  1117.     HiliteControl( buttonControl, 1 );
  1118.     Delay( 6, &lastTicks );
  1119.     HiliteControl( buttonControl, 0 );
  1120. }
  1121.  
  1122.  
  1123. /******************************************************************************\
  1124. * NAME & SYNOPSIS:
  1125. * RestoreColorsPalette: Restore all screens to the default color table
  1126. *
  1127. * PARAMETERS:
  1128. * See ColorReset.h
  1129. *
  1130. * DEFINITION:
  1131. * See ColorReset.h
  1132. *
  1133. * DESCRIPTION:
  1134. * To change the color table of any screen using the Palette Manager, a window
  1135. * must be used.  But all we want to do is reset the color tables, not display a
  1136. * window.  The obvious solution is to make a very small, inconspicuous window
  1137. * that’s tough to notice, and that’s what RestoreColorsPalette does.  A 1 pixel
  1138. * by 1 pixel is created, and a 1-entry palette is made and attached to the
  1139. * window, just so that it has a palette that can be set to the right size and
  1140. * colors later.
  1141. *
  1142. * Each screen can have different depths, and each can be gray-scale or colors,
  1143. * so every screen has have its colors set individually.  Since all we have is a
  1144. * 1 pixel by 1 pixel window, there’s not much choice here anyway.  To run
  1145. * through each screen, the GDevice list is used.  The GDevice list is a linked
  1146. * list of GDevice records that the system maintains, and there’s one GDevice
  1147. * record for every screen that’s attached to a Macintosh.  Each screen’s GDevice
  1148. * can be used to find out the screen’s depth, and whether it’s set to Grays or
  1149. * Colors mode.  See the Graphics Device Manager chapter of Inside Macintosh
  1150. * Volume VI for details. GetDeviceList is used to find the first GDevice in the
  1151. * GDevice list, and GetNextDevice is used to get the next GDevice list the list.
  1152. *
  1153. * For each GDevice in the list, it’s first tested to see if it belongs to an
  1154. * active screen.  If it doesn’t, then we just ignore it and go to the next
  1155. * GDevice in the list.  If it does, then the GDevice’s PixMap is checked to see
  1156. * what the depth of the screen is.  This depth can be passed to the GetCTable
  1157. * routine (see the Color Manager chapter of Inside Macintosh Volume V for
  1158. * details about this routine) to get a color table filled with the default
  1159. * colors for the screen depth.  As of 32-Bit QuickDraw 1.0 and/or system
  1160. * software version 6.0.5, the color table of a screen is guaranteed to contain
  1161. * the highlight color, and if you add 64 to the pixel depth and pass the result
  1162. * to GetCTable, GetCTable returns a color table filled with the default colors
  1163. * including the highlight color, and so that’s what I pass to GetCTable for a
  1164. * screen set to Colors mode.  For gray-scale screens, you add 32 to the pixel
  1165. * depth to have GetCTable return a color table filled with the default gray-
  1166. * scale color table.
  1167. *
  1168. * I pass whatever color table GetCTable returns to CTab2Palette, and I use a
  1169. * usage mode of pmTolerant + pmExplicit.  This mode is just like pmTolerant, but
  1170. * it guarantees that the palette colors are put into the screen’s color table in
  1171. * the same order that they appear in the palette when that palette is activated.
  1172. * If you just use pmTolerant, the order of colors in the screen’s color table
  1173. * will likely be scrambled, so the screen has the default colors, but not in the
  1174. * default order.
  1175. *
  1176. * Once the palette is set up with the default colors for the screen we’re
  1177. * working on, the 1 pixel by 1 pixel window is moved to the extreme upper-left
  1178. * corner of the screen, then it’s shown and immediately hidden.  The moment the
  1179. * window is shown, the screen’s color table is filled with the default colors in
  1180. * the default order.  Then we move on to the next screen until all screens have
  1181. * been handled.
  1182. *
  1183. * RETURN VALUES:
  1184. * See ColorReset.h
  1185. \******************************************************************************/
  1186.  
  1187. void RestoreColorsPalette()
  1188. {
  1189.     WindowPtr     tinyWindow;    /* Pointer to tiny window */
  1190.     CTabHandle    defaultColors; /* Default color table for the screen */
  1191.     PaletteHandle tinyPalette;   /* Palette to express defaultColors */
  1192.     Rect          tinyRect;      /* Rectangle of tiny window */
  1193.     GDHandle      screenDevice;  /* Handle to each screen’s GDevice */
  1194.     Point         screenCorner;  /* Global coordinate of top-left of each screen */
  1195.     short         clutID;        /* ID of table of default colors */
  1196.  
  1197.     /* Make the tiny window for attaching our palette */
  1198.     SetRect( &tinyRect, 0, 0, 1, 1 );
  1199.     tinyWindow = NewCWindow(
  1200.             nil,
  1201.             &tinyRect,
  1202.             "\P",
  1203.             false,
  1204.             plainDBox,
  1205.             (WindowPtr)-1,
  1206.             false,
  1207.             0L );
  1208.  
  1209.     /* Make a palette; it’s just a placeholder for the moment */
  1210.     tinyPalette = NewPalette( 1, nil, pmTolerant + pmExplicit, 0 );
  1211.     SetPalette( tinyWindow, tinyPalette, false );
  1212.  
  1213.     /* Loop through each screen GDevice to reset its screen’s colors */
  1214.     screenDevice = GetDeviceList();
  1215.     while (screenDevice != nil)
  1216.     {
  1217.         if (TestDeviceAttribute( screenDevice, screenActive ))
  1218.         {
  1219.             /* Grab default color table for the screen */
  1220.             clutID = (**(**screenDevice).gdPMap).pixelSize;
  1221.             if (TestDeviceAttribute (screenDevice, gdDevType ))
  1222.                 clutID += 64;
  1223.             else
  1224.                 clutID += 32;
  1225.             defaultColors = GetCTable( clutID );
  1226.  
  1227.             /* Convert default screen colors to a tolerant palette */
  1228.             CTab2Palette( defaultColors, tinyPalette, pmTolerant + pmExplicit, 0 );
  1229.  
  1230.             /* Don’t need that clut any more */
  1231.             DisposeCTable( defaultColors );
  1232.  
  1233.             /* Move the tiny window into the upper left corner of the screen */
  1234.             screenCorner.h = (**screenDevice).gdRect.left;
  1235.             screenCorner.v = (**screenDevice).gdRect.top;
  1236.             
  1237.             MoveWindow( tinyWindow, screenCorner.h, screenCorner.v, false );
  1238.             ShowWindow( tinyWindow );
  1239.             HideWindow( tinyWindow );
  1240.         }
  1241.  
  1242.     /* Go to the next screen in the device list */
  1243.     screenDevice = GetNextDevice( screenDevice );
  1244.     }
  1245.  
  1246.     /* Get rid of the window and palette */
  1247.     DisposePalette( tinyPalette );
  1248.     DisposeWindow( tinyWindow );
  1249. }
  1250.  
  1251.  
  1252. /******************************************************************************\
  1253. * NAME & SYNOPSIS:
  1254. * RestoreColorsSlam: Restore all screens to the default color table
  1255. *
  1256. * PARAMETERS:
  1257. * See ColorReset.h
  1258. *
  1259. * DEFINITION:
  1260. * See ColorReset.h
  1261. *
  1262. * DESCRIPTION:
  1263. * 32-Bit QuickDraw 1.0 and system software version 6.0.5 introduced a new
  1264. * routine called RestoreDeviceClut which sets the color table of specific
  1265. * screens or all the screens to the default set of colors.  RestoreColorsSlam
  1266. * calls RestoreDeviceClut with a nil parameter, which restores the color table
  1267. * of all attached screens.  At this point, the screen could appear in strange
  1268. * colors because RestoreDeviceClut doesn’t cause update events to cause the
  1269. * screen to be redrawn in the new colors.  So, RestoreColorsSlam forces all the
  1270. * screens to be redrawn by calling the Window Manager routine, PaintBehind.
  1271. * This causes the entire desktop area and all windows to be redrawn.  The only
  1272. * part of the screen that isn’t guaranteed to be redrawn is the menu bar, so
  1273. * DrawMenuBar is called to make sure the menu bar is redrawn in the new colors.
  1274. *
  1275. * RETURN VALUES:
  1276. * See ColorReset.h
  1277. \******************************************************************************/
  1278.  
  1279. void RestoreColorsSlam()
  1280. {
  1281.     RestoreDeviceClut( nil );
  1282.     PaintBehind( nil, GetGrayRgn() );
  1283.     DrawMenuBar();
  1284. }
  1285.